/*
 * @Author: hzm 
 * @Date: 2020-06-20 22:30:40 
 * @Last Modified by: hzm
 * @Last Modified time: 2020-06-20 22:32:00
 */

#pragma once

#include <stdio.h>

#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/async.h"
#include <mutex>

#ifdef __ANDROID__
#include "spdlog/sinks/android_sink.h"
#else
#endif


using namespace spdlog;

#define MSGKIT_NAME "HeyIM"

#ifdef __ANDROID__
#define MSGKIT_FILE_NAME "sdcard"
#else
#define MSGKIT_FILE_NAME "HeyIM"
#endif

namespace HeyIM {


/// MessageKit日志类，可以用来开启sdk日志，并写入到磁盘
class MLog {
    
public:
    static MLog& Instance();
    
    void InitMLog(const std::string& loggerName, const std::string& fileName, level::level_enum logLevel);
    
    /**
     开启log写入功能
     */
    void OpenTraceLog();
    
    void EndLog();
    
    void SetLevel(level::level_enum level = spdlog::level::info);
    
    template<typename... Args>
    inline void printLogD(string_view_t fmt, const Args &... args) {
        if(m_logger == nullptr) {
            return;
        }
        m_logger -> debug(fmt, args...);
    }
    
    template<typename... Args>
    inline void printLogI(string_view_t fmt, const Args &... args) {
        if(m_logger == nullptr) {
            return;
        }
        m_logger -> info(fmt, args...);
    }
    
    template<typename... Args>
    inline void printLogW(string_view_t fmt, const Args &... args) {
        if(m_logger == nullptr) {
            return;
        }
        m_logger -> warn(fmt, args...);
    }
    
    template<typename... Args>
    inline void printLogE(string_view_t fmt, const Args &... args) {
        if(m_logger == nullptr) {
            return;
        }
        m_logger -> error(fmt, args...);
    }
    
    template<typename... Args>
    inline void printLogC(string_view_t fmt, const Args &... args) {
        if(m_logger == nullptr) {
            return;
        }
        m_logger -> critical(fmt, args...);
    }
    
    template<typename... Args>
    void trace(string_view_t fmt, const Args &... args)
    {
        m_logOpenMutex.lock();
        if(m_isLogWriteToFile == false) {
            m_logOpenMutex.unlock();
            return;
        }
        m_logOpenMutex.unlock();
        m_logger -> trace(fmt, args...);
    }
    
protected:
    
    void setupLogger(const std::string& loggerName);
    void getCurrentTimeStr(std::string&) const;
    bool logFileExist(const std::string& name);
    void start();
    
protected:
    
    std::shared_ptr<logger> m_logger = nullptr;
    
    bool m_isLogWriteToFile = false;
    std::string loggerName;
    std::mutex m_logOpenMutex;
    
    std::string m_logFilePath;
    
    level::level_enum m_level = level::trace;
    
private:
    
    MLog();
    ~MLog();
    MLog(const MLog &other) = delete;
    MLog& operator=(const MLog &other) = delete;
    
};

}

#ifndef SUFFIX
//在错误级别的日志后面追加文件名，函数名，行号
#define SUFFIX(msg) std::string(msg).append("  <")\
.append(__FILENAME__).append("> <").append(__FUNCTION__)\
.append("> <").append(std::to_string(__LINE__))\
.append(">").c_str()
#endif //suffix

#define __FILENAME__ (strrchr(__FILE__,'/')?(strrchr(__FILE__,'/')+1):__FILE__)

/*
 日志等级：trace,debug,info,warn,err ,critical
 写入文件
 MLog::Instance().InitMLog("IMLog", "IMLog.txt");
 注：使用{}格式化字符串，里面的数字为占位符
 */

#define MLogTrace(msg,...)  MLog::Instance().trace(SUFFIX(msg),__VA_ARGS__)
#define MLogDebug(...)  MLog::Instance().printLogD(__VA_ARGS__)
#define MLogInfo(...)  MLog::Instance().printLogI(__VA_ARGS__)
#define MLogWarn(...) MLog::Instance().printLogW(__VA_ARGS__)
#define MLogError(msg,...)  MLog::Instance().printLogE(SUFFIX(msg),__VA_ARGS__)
#define MLogCritical(...)  MLog::Instance().printLogC(__VA_ARGS__)
